﻿<!DOCTYPE html>
<html class="theme theme-white">
<head>
<meta charset="utf-8">
<title>Java面试题之多线程(四)</title>
<link href="https://www.zybuluo.com/static/assets/template-theme-white.css" rel="stylesheet" media="screen">
<style type="text/css">

#wmd-preview h1  {
    color: #0077bb; /* 将标题改为蓝色 */
}</style>
</head>
<body class="theme theme-white">
<div id="wmd-preview" class="wmd-preview wmd-preview-full-reader"><div class="md-section-divider"></div><div class="md-section-divider"></div><h1 data-anchor-id="q93z" id="java面试题之多线程四">Java面试题之多线程(四)</h1><p data-anchor-id="wekn"><code>Java面试题</code> <code>多线程</code></p><hr><div class="md-section-divider"></div><h3 data-anchor-id="f9qd" id="如何写代码来解决生产者消费者问题">如何写代码来解决生产者消费者问题？</h3><p data-anchor-id="jkvk">在现实中你解决的许多线程问题都属于生产者消费者模型，就是一个线程生产任务供其它线程进行消费，你必须知道怎么进行线程间通信来解决这个问题。比较低级的办法是用wait和notify来解决这个问题，比较赞的办法是用Semaphore 或者 BlockingQueue来实现生产者消费者模型，<a href="http://javarevisited.blogspot.sg/2012/02/producer-consumer-design-pattern-with.html" target="_blank">这篇教程</a>有实现它。</p><div class="md-section-divider"></div><h3 data-anchor-id="fc4g" id="有三个线程t1t2t3怎么确保它们按顺序执行">有三个线程T1，T2，T3，怎么确保它们按顺序执行？</h3><p data-anchor-id="3tay">在多线程中有多种方法让线程按特定顺序执行，你可以用线程类的join()方法在一个线程中启动另一个线程，另外一个线程完成该线程继续执行。为了确保三个线程的顺序你应该先启动最后一个(T3调用T2，T2调用T1)，这样T1就会先完成而T3最后完成。</p><div class="md-section-divider"></div><h3 data-anchor-id="6blj" id="单例模式的双检锁是什么">单例模式的双检锁是什么？</h3><p data-anchor-id="ff7r">这个问题在Java面试中经常被问到，但是面试官对回答此问题的满意度仅为50%。一半的人写不出双检锁还有一半的人说不出它的隐患和Java1.5是如何对它修正的。它其实是一个用来创建线程安全的单例的老方法，当单例实例第一次被创建时它试图用单个锁进行性能优化，但是由于太过于复杂在JDK1.4中它是失败的，我个人也不喜欢它。无论如何，即便你也不喜欢它但是还是要了解一下，因为它经常被问到。你可以查看how double checked locking on Singleton works这篇文章获得更多信息</p><div class="md-section-divider"></div><h3 data-anchor-id="s947" id="如何在java中创建线程安全的singleton">如何在Java中创建线程安全的Singleton？</h3><p data-anchor-id="94k1">这是上面那个问题的后续，如果你不喜欢双检锁而面试官问了创建Singleton类的替代方法，你可以利用JVM的类加载和静态变量初始化特征来创建Singleton实例，或者是利用枚举类型来创建Singleton，我很喜欢用这种方法。你可以查看这篇文章获得更多信息。</p><div class="md-section-divider"></div><h3 data-anchor-id="si84" id="写出3条你遵循的多线程最佳实践">写出3条你遵循的多线程最佳实践</h3><div class="md-section-divider"></div><h4 data-anchor-id="r76p" id="给你的线程起个有意义的名字">给你的线程起个有意义的名字。</h4><p data-anchor-id="1t32">这样可以方便找bug或追踪。OrderProcessor, QuoteProcessor or TradeProcessor 这种名字比 Thread-1. Thread-2 and Thread-3 好多了，给线程起一个和它要完成的任务相关的名字，所有的主要框架甚至JDK都遵循这个最佳实践。</p><div class="md-section-divider"></div><h4 data-anchor-id="iwgf" id="避免锁定和缩小同步的范围">避免锁定和缩小同步的范围</h4><p data-anchor-id="agpj">锁花费的代价高昂且上下文切换更耗费时间空间，试试最低限度的使用同步和锁，缩小临界区。因此相对于同步方法我更喜欢同步块，它给我拥有对锁的绝对控制权。 <br>
多用同步类少用wait 和 notify 首先，CountDownLatch, Semaphore, CyclicBarrier 和 Exchanger 这些同步类简化了编码操作，而用wait和notify很难实现对复杂控制流的控制。其次，这些类是由最好的企业编写和维护在后续的JDK中它们还会不断优化和完善，使用这些更高等级的同步工具你的程序可以不费吹灰之力获得优化。</p><div class="md-section-divider"></div><h4 data-anchor-id="uvz7" id="多用并发集合少用同步集合">多用并发集合少用同步集合</h4><p data-anchor-id="zlgc">这是另外一个容易遵循且受益巨大的最佳实践，并发集合比同步集合的可扩展性更好，所以在并发编程时使用并发集合效果更好。如果下一次你需要用到map，你应该首先想到用ConcurrentHashMap。</p><div class="md-section-divider"></div><h3 data-anchor-id="5sy4" id="你如何确保main方法所在的线程是java程序最后结束的线程">你如何确保main()方法所在的线程是Java程序最后结束的线程？</h3><div class="md-section-divider"></div><h3 data-anchor-id="htog" id="同步方法和同步块哪个是更好的选择">同步方法和同步块，哪个是更好的选择？</h3><div class="md-section-divider"></div><h3 data-anchor-id="crlx" id="数组a内容为-123452-数组b内容为26个英文字母使用两个线程分别输入两个数组打印内容为12a34b56c78e-这样的规律">数组A内容为 1,2,3,4...52 ,数组B内容为26个英文字母，使用两个线程分别输入两个数组，打印内容为：12a34b56c78e....... 这样的规律</h3><div class="md-section-divider"></div><h3 data-anchor-id="2z7m" id="列举出一般情况下线程中断的几种方式并说明他们之间的优缺点并且说明那种中断方式最好">列举出一般情况下线程中断的几种方式,并说明他们之间的优缺点,并且说明那种中断方式最好</h3><div class="md-section-divider"></div><h3 data-anchor-id="2s59" id="在java中lock接口比synchronized块的优势是什么你需要实现一个高效的缓存它允许多个用户读但只允许一个用户写以此来保持它的完整性你会怎样去实现它">在Java中Lock接口比synchronized块的优势是什么？你需要实现一个高效的缓存，它允许多个用户读，但只允许一个用户写，以此来保持它的完整性，你会怎样去实现它？</h3><div class="md-section-divider"></div><h3 data-anchor-id="emu9" id="用java实现阻塞队列">用Java实现阻塞队列</h3><div class="md-section-divider"></div><h3 data-anchor-id="i0p3" id="用java编程一个会导致死锁的程序你将怎么解决">用Java编程一个会导致死锁的程序，你将怎么解决？</h3><div class="md-section-divider"></div><h3 data-anchor-id="pf98" id="你将如何使用thread-dump你将如何分析thread-dump">你将如何使用thread dump？你将如何分析Thread dump？</h3><div class="md-section-divider"></div><h3 data-anchor-id="ki7m" id="你在多线程环境中遇到的常见的问题是什么你是怎么解决它的">你在多线程环境中遇到的常见的问题是什么？你是怎么解决它的？</h3><div class="md-section-divider"></div><h3 data-anchor-id="2pgd" id="现有的程序代码模拟产生了16个日志对象并且需要运行16秒才能打印完这些日志请在程序中增加4个线程去调用parselog方法来分头打印这16个日志对象程序只需要运行4秒即可打印完这些日志对象">现有的程序代码模拟产生了16个日志对象，并且需要运行16秒才能打印完这些日志，请在程序中增加4个线程去调用parseLog()方法来分头打印这16个日志对象，程序只需要运行4秒即可打印完这些日志对象。</h3><div class="md-section-divider"></div><h3 data-anchor-id="s2ss" id="现成程序中的test类中的代码在不断地产生数据然后交给testdodosome方法去处理就好像生产者在不断地产生数据消费者在不断消费数据请将程序改造成有10个线程来消费生成者产生的数据这些消费者都调用testdodosome方法去进行处理故每个消费者都需要一秒才能处理完程序应保证这些消费者线程依次有序地消费数据只有上一个消费者消费完后下一个消费者才能消费数据下一个消费者是谁都可以但要保证这些消费者线程拿到的数据是有顺序的">现成程序中的Test类中的代码在不断地产生数据，然后交给TestDo.doSome()方法去处理，就好像生产者在不断地产生数据，消费者在不断消费数据。请将程序改造成有10个线程来消费生成者产生的数据，这些消费者都调用TestDo.doSome()方法去进行处理，故每个消费者都需要一秒才能处理完，程序应保证这些消费者线程依次有序地消费数据，只有上一个消费者消费完后，下一个消费者才能消费数据，下一个消费者是谁都可以，但要保证这些消费者线程拿到的数据是有顺序的。</h3><div class="md-section-divider"></div><h3 data-anchor-id="acz7" id="现有程序同时启动了4个线程去调用testdodosomekey-value方法由于testdodosomekey-value方法内的代码是先暂停1秒然后再输出以秒为单位的当前时间值所以会打印出4个相同的时间值如下所示">现有程序同时启动了4个线程去调用TestDo.doSome(key, value)方法，由于TestDo.doSome(key, value)方法内的代码是先暂停1秒，然后再输出以秒为单位的当前时间值，所以，会打印出4个相同的时间值，如下所示：</h3><p data-anchor-id="2q60">4:4:1258199615 <br>
1:1:1258199615 <br>
3:3:1258199615 <br>
1:2:1258199615 <br>
请修改代码，如果有几个线程调用TestDo.doSome(key, value)方法时，传递进去的key相等（equals比较为true），则这几个线程应互斥排队输出结果，即当有两个线程的key都是"1"时，它们中的一个要比另外其他线程晚1秒输出结果，如下所示： <br>
4:4:1258199615 <br>
1:1:1258199615 <br>
3:3:1258199615 <br>
1:2:1258199616 <br>
总之，当每个线程中指定的key相等时，这些相等key的线程应每隔一秒依次输出时间值（要用互斥），如果key不同，则并行执行（相互之间不互斥）。</p><div class="md-section-divider"></div><h3 data-anchor-id="af5a" id="结束">结束</h3></div>
</body>
</html>